-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local log = require 'mc.logging'
local class = require 'mc.class'
local bios_enum = require 'domain.bios_firmware.defs'
local vos = require 'utils.vos'
local bs_util = require 'util.base_util'
local imu_communicate = require 'domain.transport.imu_communicate'
local PackageSnapshot = class()


local function select_info_db(db, system_id)
    local db_id = 'BiosCfg'
    if system_id ~= 1 then
        db_id = 'BiosCfg_' .. system_id
    end
    local db_info = db:select(db.BiosUpdateCfgTable)
        :where(db.BiosUpdateCfgTable.Id:eq(db_id)):first()
    if db_info then
        return db_info
    end
    local new_db_info = db.BiosUpdateCfgTable({
        Id = db_id,
        idex = '0',
        UpgradeFinishFlag = true,
        Version = '',
        EffectiveFlag = false,
        PackageType = 0,
        Period = 0})
    new_db_info:save()
    return new_db_info
end

-- 升级包快照：包含升级包属性，是否异常中断等
function PackageSnapshot:ctor(db, obj, system_id)
    self.db = db
    self.obj = obj
    local db_info = select_info_db(db, system_id)
    self.DbInfo = db_info
    -- 升级包类型：正常包、补丁包
    self.PackageType = db_info.PackageType
    self.Period = db_info.Period
    -- 升级是否完整
    self.UpgradeFinishFlag = db_info.UpgradeFinishFlag
    -- 升级包版本
    self.Version = db_info.Version
    -- 升级包是否生效
    self.EffectiveFlag = db_info.EffectiveFlag
    self.obj.ActivatedStatus = db_info.EffectiveFlag
    -- 缓存包路径
    self.CachePath = bs_util.get_bios_cached_path(system_id)
    self.SystemId = system_id
    -- 普通固件升级包是否生效
    self.obj.FirmwareEffectiveStatus = db_info.FirmwareEffectiveStatus
    self.SlaveUpgrade = db_info.SlaveUpgrade
    log:notice('[bios]package snapshot system %s slave upgrade is %s', system_id, self.SlaveUpgrade)
end

-- 1、支持查询是否有异常中断
-- 2、支持查询缓存包路径
-- 3、支持查询缓存包属性

function PackageSnapshot:_Persistence(prop, val)
    self[prop] = val
    if self.DbInfo[prop] ~= nil then
        self.DbInfo[prop] = val
        self.DbInfo:save()
    end
end

function PackageSnapshot:get_system_id()
    return self.SystemId
end

function PackageSnapshot:upgrade_start()
    self:_Persistence('UpgradeFinishFlag', false)
end

function PackageSnapshot:upgrade_finish()
    self:_Persistence('UpgradeFinishFlag', true)
end

function PackageSnapshot:set_period(period)
    self:_Persistence('Period', period)
end

function PackageSnapshot:set_package_type(package_type)
    self:_Persistence('PackageType', package_type)
end

function PackageSnapshot:set_version(version)
    self:_Persistence('Version', version)
end

function PackageSnapshot:set_effective(flag)
    self:_Persistence('EffectiveFlag', flag)
    self.obj.ActivatedStatus = flag
end

function PackageSnapshot:set_slave_upgrade(flag)
    self:_Persistence('SlaveUpgrade', flag)
end

function PackageSnapshot:set_firmware_effective_status(flag)
    self:_Persistence('FirmwareEffectiveStatus', flag)
    self.obj.FirmwareEffectiveStatus = flag
end

function PackageSnapshot:set_cache_path(cache_path)
    self.CachePath = cache_path
end

function PackageSnapshot:is_complete()
    if self.UpgradeFinishFlag ~= bios_enum.UpgradeFlag.Finish and
        vos.get_file_accessible(self.CachePath) then
        log:error('[bios]package snapshot interrupt: flag(%s)', self.UpgradeFinishFlag)
        return false
    end
    log:notice('[bios]package snapshot complete: flag(%s)', self.UpgradeFinishFlag)
    return true
end

function PackageSnapshot:is_cache()
    return vos.get_file_accessible(self.CachePath)
end

function PackageSnapshot:get_package_type()
    return self.PackageType
end

function PackageSnapshot:get_period()
    return self.Period
end

function PackageSnapshot:get_effective_flag()
    return self.EffectiveFlag
end

function PackageSnapshot:get_version()
    return self.Version
end

function PackageSnapshot:get_slave_upgrade()
    return self.SlaveUpgrade
end

function PackageSnapshot:get_preserve_config_enabled()
    return self.obj.PreserveConfigEnabled
end

local STATUS_INVALID = -1
function PackageSnapshot:activate(bitmap)
    log:notice('[bios]package snapshot: effectivat status(%s)', self.EffectiveFlag)
    if self.EffectiveFlag ~= bios_enum.ActivateStatus.Begin then
        log:error('[bios]package snapshot: effectivat status invalid')
        error({Code = STATUS_INVALID})
    end
    local ok, res = pcall(function()
        local imu_cmd = imu_communicate.get_instance()
        imu_cmd:activate(bitmap, self.SystemId)
        log:notice('[bios]package snapshot: activate bitmap(0x%0x)', bitmap)
        self:set_effective(bios_enum.ActivateStatus.Running)
    end)
    if not ok then
        self:set_effective(bios_enum.ActivateStatus.Begin)
        error(res)
    end
end

return PackageSnapshot